<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8" />
		<title>JS算法题</title>
	</head>
	<body>
		<h3>question1.回溯解决N皇后问题</h3>
		<button type="button" onclick="solveNQueens(8)">question1运行</button><!-- 这道是力扣上的算法题有一点难 -->
		
		<h3>question2.JS函数柯里化</h3>
		<h5>经典面试题：实现add(1)(2)(3)(4)=10;add(1)(1,2,3)(2)=9;
		指的是将一个接受多个参数的函数 变为接受一个参数返回一个函数的固定形式
		这样便于再次调用，且不定参数传几个,灵活且方便。例如f(1)(2)</h5>
		<button type="button" onclick="console.log(add(1,2,3)==6)">question2运行</button>
		<button type="button" onclick="console.log(add(1)(2)(4))">question2运行</button>
		<h5>柯里化（Currying）是把接受多个参数的函数变换成接受一个单一参数（最初函数的第一个参数）的函数，并且返回接受余下的参数而且返回结果的新函数的技术。</h5>
		<h5> 查阅了一些资料发现这个方法并不是完全真正的实现了柯里化,方法太老了。并没有实现预期结果，下面测试下新方法。使得 add(1,2,3,,,) === currying(add)(1,2,3,,,) </h5>
		<button type="button" onclick="console.log(newAdd(1,2,3)) ">新方法newAdd</button>
		<button type="button" onclick="console.log( currying(newAdd)(1,2,3)) ">新方法newAddcurrying</button>
		
		<br><br>
		<button type="button" onclick="window.open('js_math.html')">跳转JS基础</button>
	</body>
	<script type="text/javascript">
		//question1.皇后题参考链接https://cloud.tencent.com/developer/article/1718735作者ssh1995
		/**
		 * @param {number} n
		 * @return {string[][]}
		 */
		let solveNQueens = function (n) {
		  let res = []
		
		  // 已摆放皇后的的列下标
		  let columns = []
		  // 已摆放皇后的对角线1下标 左下 -> 右上
		  // 计算某个坐标是否在这个对角线的方式是「行下标 + 列下标」是否相等
		  let dia1 = []
		  // 已摆放皇后的对角线2下标 左上 -> 右下
		  // 计算某个坐标是否在这个对角线的方式是「行下标 - 列下标」是否相等
		  let dia2 = []
		
		  // 在选择当前的格子后 记录状态
		  let record = (rowIndex, columnIndex, bool) => {
		    columns[columnIndex] = bool
		    dia1[rowIndex + columnIndex] = bool
		    dia2[rowIndex - columnIndex] = bool
		  }
		
		  // 尝试在一个n皇后问题中 摆放第index行内的皇后位置
		  let putQueen = (rowIndex, prev) => {
		    if (rowIndex === n) {
		      res.push(generateBoard(prev))
		      return
		    }
		
		    // 尝试摆第index行的皇后 尝试[0, n-1]列
		    for (let columnIndex = 0; columnIndex < n; columnIndex++) {
		      // 在列上不冲突
		      let columnNotConflict = !columns[columnIndex]
		      // 在对角线1上不冲突
		      let dia1NotConflict = !dia1[rowIndex + columnIndex]
		      // 在对角线2上不冲突
		      let dia2NotConflict = !dia2[rowIndex - columnIndex]
		
		      if (columnNotConflict && dia1NotConflict && dia2NotConflict) {
		        // 都不冲突的话，先记录当前已选位置，进入下一轮递归
		        record(rowIndex, columnIndex, true)
		        putQueen(rowIndex + 1, prev.concat(columnIndex))
		        // 递归出栈后，在状态中清除这个位置的记录，下一轮循环应该是一个全新的开始。
		        record(rowIndex, columnIndex, false)
		      }
		    }
		  }
		
		  putQueen(0, [])
		  console.log(res)
		
		  return res
		}
		
		// 生成二维数组的辅助函数
		function generateBoard(row) {
		  let n = row.length
		  let res = []
		  for (let y = 0; y < n; y++) {
		    let cur = ""
		    for (let x = 0; x < n; x++) {
		      if (x === row[y]) {
		        cur += "Q"
		      } else {
		        cur += "."
		      }
		    }
		    res.push(cur)
		  }
		  return res
		}
		//question2.JS函数柯里化。参考老陈打码https://www.bilibili.com/video/BV1Cy4y1q7xz?share_medium=web&share_source=qq&bbid=15497BCE-9A60-483C-ACC9-143EE9B0DFB153944infoc&ts=1606114647129
		function add(..._args){
			//将传入的不定参数转换为数组对象
			//console.log(arguments)  //arguments 是一个对应于传递给函数的参数的类数组对象。
			//call：调用一个对象的一个方法，用另一个对象替换当前对象。例如：B.call(A, args1,args2);即A对象调用B对象的方法。
			//var _args = Array.prototype.slice.call(arguments)//arguments调用了数组的slice方法复制了一份自己 。这行代码用es6的rest运算符实现
			//console.log(_args)     //此时的_args是一个有值的数组
			let _adder =function (){
				//把_adder的参数也加入到_args里面
				_args.push(...arguments)//push可以放一个值也可以放多个值。把_adder的参数arguments解构推送到_args里面
				//扩展运算符用三个点号表示，功能是把数组或类数组对象展开成一系列用逗号隔开的值
				//延伸：rest运算符也是三个点号，不过其功能与扩展运算符恰好相反，把逗号隔开的值序列组合成一个数组。
				// rest运算符 主要用于不定参数，所以ES6开始可以不再使用arguments对象
				return _adder
			}
			//当前返回的是函数，没有相加结果。接下来用toString隐性转换的特性改写一下			
			_adder.toString = function(){
				return _args.reduce(function(a,b){
					return a+b 
				},0)
			}
			//reduce() 方法接收一个函数作为累加器，数组中的每个值（从左到右）开始缩减，最终计算为一个值。
			return _adder	
		}
		//打印结果 f 6 既是函数又是字符串6 
		//question2新方法参考博文https://www.cnblogs.com/mingweiyard/p/14000209.html
	   let newAdd =(...args) => args.reduce((a,b)=>a+b)
	   let currying = (fn)=>{
		   return function(...args){
			   return fn.apply(this,args)
		   }
	   }
		

	</script>
</html>
